(library (lib list-procs)
  (export rest
          range
          enumerate
          flatten
          filter*)
  (import
    (except (rnrs base) let-values map error)
    (only (guile)
          ;; lambda forms
          lambda* λ
          ;; conditionals
          when
          ;; input output
          simple-format
          current-output-port
          call-with-output-string
          current-input-port
          ;; strings
          string-trim
          string-join
          string-append
          string-delete
          ;; other
          error)
    ;; srfi-1 for list procedures
    (srfi srfi-1)

    (lib string-procs)
    (prefix (lib logger) log:)))


(define rest cdr)


(define range
  (lambda* (start end #:key (end-inclusive #f) (start-inclusive #t) (step 1))
    (cond
     [(> start end) '()]
     [(= start end)
      (cond [end-inclusive (cons end '())]
            [else '()])]
     [else
      (cond [start-inclusive
             (cons start
                   (range (+ start step)
                          end
                          #:end-inclusive end-inclusive
                          #:step step))]
            [else
             (range (+ start step)
                    end
                    #:end-inclusive end-inclusive
                    #:start-inclusive #t  ; change after first element
                    #:step step)])])))


(define flatten
  (λ (lst)
    (cond [(null? lst) '()]
          [(pair? lst)
           (append (flatten (car lst))
                   (flatten (cdr lst)))]
          [else
           (list lst)])))


(define filter*
  (λ (pred lst-or-atom)
    (log:debug (string-format "remaining lst-or-atom: ~a" lst-or-atom))
    (cond
     [(null? lst-or-atom) '()]
     [(pair? lst-or-atom)
      (cond
       [(pair? (car lst-or-atom))
        (cons (filter* pred (car lst-or-atom))
              (filter* pred (cdr lst-or-atom)))]
       [else
        (cond
         [(pred (car lst-or-atom))
          (cons (car lst-or-atom)
                (filter* pred (cdr lst-or-atom)))]
         [else
          (filter* pred (cdr lst-or-atom))])])]
     [(pred lst-or-atom) lst-or-atom]
     [else '()])))


(define enumerate
  (lambda* (lst #:key (start 0) (step 1))
    (range start (length lst) #:step 1)))
